/*
* Copyright (C) 2012 chao,Wu Tong
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cocoa4android.ui;
import java.util.ArrayList;
import java.util.List;
import org.cocoa4android.cg.CGRect;
import org.cocoa4android.ns.NSArray;
import org.cocoa4android.ns.NSIndexPath;
import org.cocoa4android.ui.UITableViewCell.UITableViewCellSelectionStyle;
import org.cocoa4android.ui.UITableViewCell.UITableViewCellShapeType;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AbsListView.LayoutParams;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
public class UITableView extends UIView {
private ListView listView = null;
private CocoaAdapter adapter = null;
private UITableViewDataSource dataSource = null;
private UITableViewDelegate delegate = null;
private boolean scrollEnabled = YES;
private boolean enableMutipleScroll = NO;
public boolean isEnableMutipleScroll() {
return enableMutipleScroll;
}
public void setEnableMutipleScroll(boolean enableMutipleScroll) {
this.enableMutipleScroll = enableMutipleScroll;
}
private UITableViewStyle style;
UITableViewCellSeparatorStyle cellSeparatorStyle;
private boolean isGrouped;
private List<NSIndexPath> mappingList = null;//mapping position to indexPath
private List<UIView> cellsList = null;
private UIView selectedView = null;
private UIColor selectedColor = null;
private NSIndexPath selectedIndexPath = null;
public UITableView() {
this(UITableViewStyle.UITableViewStylePlain);
}
public UITableViewCell reuseCell;
public UITableView(UITableViewStyle style) {
this.style = style;
listView = new CocoaListView(context);
listView.setBackgroundColor(Color.GRAY);
listView.setDrawingCacheBackgroundColor(Color.WHITE);
listView.setCacheColorHint(0);
isGrouped = (style == UITableViewStyle.UITableViewStyleGrouped) ? true : false;
if(isGrouped) {
listView.setPadding((int)(10*scaleDensityX), (int)(10*scaleDensityY), (int)(10*scaleDensityX), (int)(25*scaleDensityX));
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
if(selectedView != null){
UITableViewCell cell = (UITableViewCell)selectedView;
if (cell.selectionStyle()!=UITableViewCellSelectionStyle.UITableViewCellSelectionStyleNone) {
selectedView.setBackgroundColor(selectedColor);
}
listView.invalidate();
if (delegate != null) {
delegate.disDeselectRowAtIndexPath(UITableView.this, selectedIndexPath);
}
}
selectedView = cellsList.get(position);
//incase click the foot or head
if (selectedView!=null) {
if (UITableViewCell.class.isInstance(selectedView)) {
selectedIndexPath = mappingList.get(position);
selectedColor = selectedView.backgroundColor();
UITableViewCell cell = (UITableViewCell)selectedView;
if (cell.selectionStyle()==UITableViewCellSelectionStyle.UITableViewCellSelectionStyleBlue) {
cell.setBackgroundColor(new UIColor(0xff0378f0));
}else if(cell.selectionStyle() == UITableViewCellSelectionStyle.UITableViewCellSelectionStyleGray){
cell.setBackgroundColor(new UIColor(0xffaaaaaa));
}else if(cell.selectionStyle()==UITableViewCellSelectionStyle.UITableViewCellSelectionStyleNone){
//do nothing
}
listView.invalidate();
if(delegate != null) {
delegate.didSelectRowAtIndexPath(UITableView.this, selectedIndexPath);
}
}else{
selectedView = null;
}
}
}
});
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return !scrollEnabled;
}
});
listView.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_OVERLAY);
listView.setSelector(new ColorDrawable(Color.TRANSPARENT));
RelativeLayout layout = new RelativeLayout(context);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
layout.setLayoutParams(params);
this.setView(layout);
LayoutParams listparams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
listView.setLayoutParams(listparams);
layout.addView(listView);
}
public UITableView(CGRect frame) {
this();
this.setFrame(frame);
}
public UITableViewStyle style() {
return style;
}
@Override
protected void setSuperview(UIView superView){
super.setSuperview(superView);
}
@Override
public void setBackgroundColor(UIColor backgroundColor){
super.setBackgroundColor(backgroundColor);
listView.setBackgroundColor(backgroundColor.getColor());
if (style==UITableViewStyle.UITableViewStyleGrouped) {
listView.setDivider(new ColorDrawable(backgroundColor.getColor()));
listView.setDividerHeight(1);
if (cellSeparatorStyle!=null) {
this.setSeparatorStyle(cellSeparatorStyle);
}
}
}
private ArrayList<NSIndexPath> initMapping() {
if(dataSource != null && delegate != null) {
mappingList = new ArrayList<NSIndexPath>();
cellsList = new ArrayList<UIView>();
int numberOfSection = dataSource.numberOfSectionsInTableView(this);
int numberOfRowInSection = 0;
NSIndexPath indexPath = null;
for(int section = 0;section < numberOfSection;section++) {
mappingList.add(new NSIndexPath(section,-1));//header
cellsList.add(null);//header
numberOfRowInSection = dataSource.numberOfRowsInSection(this, section);
for(int row = 0;row < numberOfRowInSection;row++) {
indexPath = new NSIndexPath(section, row);
mappingList.add(indexPath);
cellsList.add(null);
}
mappingList.add(new NSIndexPath(section,Integer.MAX_VALUE));//footer
cellsList.add(null);//footer
}
}
return (ArrayList<NSIndexPath>) mappingList;
}
public void reloadData() {
this.initMapping();
this.sourceChanged(mappingList);
}
public void setDataSource(UITableViewDataSource dataSource) {
this.dataSource = dataSource;
this.initMapping();
}
public void setDelegate(UITableViewDelegate delegate) {
this.delegate = delegate;
this.initMapping();
}
public void selectRowAtIndexPath(NSIndexPath indexPath) {
if (cellsList != null) {
int position = mappingList.indexOf(indexPath);
if (selectedView != null) {
selectedView.setBackgroundColor(UIColor.whiteColor());
listView.invalidate();
}
selectedIndexPath = indexPath;
selectedView = cellsList.get(position);
}
}
public void deselectRowAtIndexPath(NSIndexPath indexPath) {
if (indexPath.isEqual(selectedIndexPath)) {
selectedView.setBackgroundColor(UIColor.whiteColor());
listView.invalidate();
selectedIndexPath = null;
selectedView = null;
}
}
public UITableViewCell cellForRowAtIndexPath(NSIndexPath indexPath){
int position = mappingList.indexOf(indexPath);
return (UITableViewCell) cellsList.get(position);
}
public void setSeparatorStyle(UITableViewCellSeparatorStyle style) {
switch(style) {
case UITableViewCellSeparatorStyleNone:
listView.setDividerHeight(0);
break;
case UITableViewCellSeparatorStyleSingleLine:
listView.setDividerHeight(1);
break;
case UITableViewCellSeparatorStyleSingleLineEtched:
break;
}
this.cellSeparatorStyle = style;
}
public void setSeparatorColor(UIColor color){
listView.setDivider(new ColorDrawable(color.getColor()));
listView.setDividerHeight(1);
if (cellSeparatorStyle!=null) {
this.setSeparatorStyle(cellSeparatorStyle);
}
}
//FIXME no animation
public void insertRowsAtIndexPaths(NSArray indexPaths,UITableViewRowAnimation animation) {
NSIndexPath indexPath = null;
NSIndexPath tmpIndexPath = null;
for (int i = 0; i < indexPaths.count(); i++) {
indexPath = (NSIndexPath) indexPaths.objectAtIndex(i);
int position = 0;
int count = mappingList.size();
while (true) {
int middle = (position + count) / 2;
if (middle == position) {
if (indexPath.compareTo(mappingList.get(middle)) > 0) {//indexPath is greater than last one
position = count;
}
break;
}
tmpIndexPath = mappingList.get(middle);
if (indexPath.compareTo(tmpIndexPath) > 0) {//indexPath > tmpIndexPath
position = middle;
}
else if (indexPath.compareTo(tmpIndexPath) < 0) {//indexPath < tmpIndexPath
count = middle;
}
else {//indexPath == tmpIndexPath
position = middle;
break;
}
}
mappingList.add(position, indexPath);
cellsList.add(position, null);
for(int j = position+1;j < mappingList.size();j++) {
tmpIndexPath = mappingList.get(j);
if (indexPath.section() == tmpIndexPath.section() && tmpIndexPath.row() != Integer.MAX_VALUE) {
tmpIndexPath.setRow(tmpIndexPath.row()+1);
}
else {
break;
}
}
}
this.sourceChanged(mappingList);
}
//FIXME no animation
public void deleteRowsAtIndexPaths(NSArray indexPaths,UITableViewRowAnimation animation) {
NSIndexPath indexPath = null;
mappingList.indexOf(indexPath);
for (int i = 0; i < indexPaths.count(); i++) {
indexPath = (NSIndexPath) indexPaths.objectAtIndex(i);
int position = mappingList.indexOf(indexPath);
mappingList.remove(position);
cellsList.remove(position);
}
this.sourceChanged(mappingList);
}
protected void sourceChanged(List<NSIndexPath> localMappingList) {
if (adapter!=null) {
adapter.mappingList = localMappingList;
adapter.notifyDataSetChanged();
listView.invalidateViews();
}
}
public UITableViewCell dequeueReusableCellWithIdentifier(String identifier){
if (reuseCell!=null&&reuseCell.reuseIdentifier()!=null&&reuseCell.reuseIdentifier().equals(identifier)) {
UITableViewCell cell = reuseCell;
this.reuseCell = null;
return cell;
}
return null;
}
private UIView headerView = null;
private UIView footerView = null;
public void setTableHeaderView(UIView view){
if (headerView!=null) {
listView.removeHeaderView(headerView.getView());
}
if (view!=null) {
AbsListView.LayoutParams params = null;
if(view.frame==null){
params = new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, (int)(44*scaleDensityY));
}else{
params = new AbsListView.LayoutParams((int) (view.frame.size.width*scaleDensityX), (int)(view.frame.size.height*scaleDensityY));
}
view.getView().setLayoutParams(params);
listView.addHeaderView(view.getView());
}
headerView = view;
}
public void setTableFooterView(UIView view){
if (footerView!=null) {
listView.removeFooterView(footerView.getView());
}
if (view!=null) {
listView.addFooterView(view.getView());
}
footerView = view;
}
public boolean isScrollEnabled() {
return scrollEnabled;
}
public void setScrollEnabled(boolean scrollEnabled) {
this.scrollEnabled = scrollEnabled;
}
public interface UITableViewDataSource {
int numberOfRowsInSection(UITableView tableView,int section);
UITableViewCell cellForRowAtIndexPath(UITableView tableView,NSIndexPath indexPath);
int numberOfSectionsInTableView(UITableView tableView);
}
public interface UITableViewDelegate {
float heightForRowAtIndexPath(UITableView tableView,NSIndexPath indexPath);
float heightForHeaderInSection(UITableView tableView,int section);
float heightForFooterInSection(UITableView tableView,int section);
UIView viewForHeaderInSection(UITableView tableView,int section);
UIView viewForFooterInSection(UITableView tableView,int section);
void didSelectRowAtIndexPath(UITableView tableView,NSIndexPath indexPath);
void disDeselectRowAtIndexPath(UITableView tableView,NSIndexPath indexPath);
void willDisplayCellForRowAtIndexPath(UITableView tableView,UITableViewCell cell,NSIndexPath indexPath);
}
public enum UITableViewStyle {
UITableViewStylePlain, // regular table view
UITableViewStyleGrouped // preferences style table view
}
public enum UITableViewRowAnimation {
UITableViewRowAnimationFade,
UITableViewRowAnimationRight, // slide in from right (or out to right)
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone, // available in iOS 3.0
UITableViewRowAnimationMiddle, // available in iOS 3.2. attempts to keep cell centered in the space it will/did occupy
UITableViewRowAnimationAutomatic // available in iOS 5.0. chooses an appropriate animation style for you
}
public class CocoaListView extends ListView{
public CocoaListView(Context context) {
super(context);
}
private int currX;
private int currY;
private int prevX;
private int prevY;
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b){
if (adapter==null) {
adapter = new CocoaAdapter(mappingList);
listView.setAdapter(adapter);
}
super.onLayout(changed, l, t, r, b);
}
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
super.onSizeChanged(xNew, yNew, xOld, yOld);
}
public boolean onInterceptTouchEvent(MotionEvent event) {
if (enableMutipleScroll) {
return true;
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event){
if (enableMutipleScroll) {
prevY = currY;
prevX = currX;
currY = (int) event.getY();
currX = (int)event.getX();
int deltaX = currX-prevX;
int deltaY = currY-prevY;
boolean blockTouch = true;
if (event.getAction()==MotionEvent.ACTION_MOVE) {
//if it is moved
//decide if the listview can scroll
boolean cannotScroll = YES;
if (Math.abs(deltaX)<Math.abs(deltaY)) {
cannotScroll = ((this.getCount()==this.getLastVisiblePosition()+1)&&deltaY<0)||(this.getFirstVisiblePosition()==0&&deltaY>0);
}
if(cannotScroll&&(deltaX!=0||deltaY!=0)){
blockTouch = false;
}
}
requestDisallowInterceptTouchEvent(blockTouch);
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
public class CocoaAdapter extends BaseAdapter{
public List<NSIndexPath> mappingList;
public CocoaAdapter(List<NSIndexPath> mappingList){
this.mappingList = mappingList;
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
UIView view = null;
if(dataSource != null && delegate != null) {
NSIndexPath indexPath = mappingList.get(position);
if(indexPath.row() == -1) {//header
view = delegate.viewForHeaderInSection(UITableView.this, indexPath.section);
float height = delegate.heightForHeaderInSection(UITableView.this, indexPath.section());
if(height <= 0 || view == null) {
view = new UIView();
}
view.setBackgroundColor(UIColor.clearColor());
AbsListView.LayoutParams params = new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, (int)(height*scaleDensityY));
view.getView().setLayoutParams(params);
return view.getView();
}
else if(indexPath.row() == Integer.MAX_VALUE) {//footer
view = delegate.viewForFooterInSection(UITableView.this, indexPath.section);
float height = delegate.heightForFooterInSection(UITableView.this, indexPath.section());
if(height <= 0 || view == null) {
view = new UIView();
}
view.setBackgroundColor(UIColor.clearColor());
AbsListView.LayoutParams params = new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, (int)(height*scaleDensityY));
view.getView().setLayoutParams(params);
return view.getView();
}
else {
//UITableViewCell cell = (UITableViewCell) cellsList.get(position);
UITableViewCell cell = null;
if (cell==null) {
if (convertView!=null&&UITableViewCell.class.isInstance(convertView.getTag())) {
reuseCell = (UITableViewCell) convertView.getTag();
}
cell = dataSource.cellForRowAtIndexPath(UITableView.this, indexPath);
float height = delegate.heightForRowAtIndexPath(UITableView.this, indexPath);
cell.setHeight(height);
int section = indexPath.section();
int row = indexPath.row();
int numberOfRowsInSection = dataSource.numberOfRowsInSection(UITableView.this, section);
if (row == 0 && row == numberOfRowsInSection-1) {
cell.setShapeType(UITableViewCellShapeType.UITableViewCellShapeAllRound);
}
else if (row == 0) {
cell.setShapeType(UITableViewCellShapeType.UITableViewCellShapeTopRound);
}
else if (row == numberOfRowsInSection-1) {
cell.setShapeType(UITableViewCellShapeType.UITableViewCellShapeBottomRound);
}
else {
cell.setShapeType(UITableViewCellShapeType.UITableViewCellShapeNoRound);
}
}
delegate.willDisplayCellForRowAtIndexPath(UITableView.this, cell, indexPath);
view = cell;
reuseCell = null;
}
}
if (view==null) {
return null;
}else{
cellsList.set(position, view);
return view.getView();
}
}
@Override
public int getItemViewType(int position) {
return 0;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public int getCount() {
if(dataSource != null) {
if(mappingList == null) {
mappingList = initMapping();
}
return mappingList.size();
}
return 0;
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
if(mappingList == null) {
mappingList = initMapping();
}
NSIndexPath indexPath = mappingList.get(position);
if(indexPath.row() < 0) {
return false;
}
return true;
}
}
public enum UITableViewCellSeparatorStyle {
UITableViewCellSeparatorStyleNone,
UITableViewCellSeparatorStyleSingleLine,
UITableViewCellSeparatorStyleSingleLineEtched // This separator style is only supported for grouped style table views currently
}
}